#include "common_config.h"
#include "icreader.h"
#include "twai_helper.h"

static void uart2_icreader_task(void *pvParameters)
{
    uart_event_t event;
    size_t buffered_size;
    uint8_t* dtmp = (uint8_t*) malloc(RD_BUF_SIZE);
    for(;;) {
        //Waiting for UART event.
        if(xQueueReceive(uart2_queue, (void * )&event, (TickType_t)portMAX_DELAY)) 
        {
            bzero(dtmp, RD_BUF_SIZE);
            ESP_LOGI(TAG, "uart[%d] event:", ICREADER_UART_NUM);
            switch(event.type) {
                //Event of UART receving data
                /*We'd better handler data event fast, there would be much more data events than
                other types of events. If we take too much time on data event, the queue might
                be full.*/
                case UART_DATA:
                    ESP_LOGI(TAG, "[UART DATA]: %d", event.size);
                    uart_read_bytes(ICREADER_UART_NUM, dtmp, event.size, portMAX_DELAY);
                    for(int i=0;i<event.size;i++)
                    {
                        ESP_LOGI(TAG, "[UART READ DATA[%d]]: %x\n", i, *(dtmp+i));
                    }
                    
                    if (checkData(dtmp, cardType,0, 7))
                    {
                        ESP_LOGI(TAG, "Car type correct, read 24 partition data\n");
                        uart_write_bytes(ICREADER_UART_NUM, (const char*) cmd, sizeof(cmd));
                        // vTaskDelay(50/portTICK_PERIOD_MS);
                    }
                    if (checkData(dtmp, carCmd,5,6))
                    {
                        if(pwrstate==-1)
                        {
                            gpio_set_level(GPIO_OUTPUT_IO_0, 1);
                            gpio_set_level(GPIO_OUTPUT_IO_1, 1);
                            vTaskDelay(300/portTICK_PERIOD_MS);
                            gpio_set_level(GPIO_OUTPUT_IO_2, 1);
                            ESP_LOGI(TAG, "Key power on\n");
                            vTaskDelay(300/portTICK_PERIOD_MS);
                            pwrstate = 1;
                            gpio_set_level(GPIO_OUTPUT_IO_0, 0);
                            vTaskDelay(300/portTICK_PERIOD_MS);
                            gpio_set_level(GPIO_OUTPUT_IO_0, 1);
                            ESP_LOGI(TAG, "Door opened\n");
                            dooropened = true;
                            break;
                        }
                        else if (pwrstate == 1)
                        {
                            gpio_set_level(GPIO_OUTPUT_IO_1, 0);
                            vTaskDelay(300/portTICK_PERIOD_MS);
                            gpio_set_level(GPIO_OUTPUT_IO_1, 1);
                            ESP_LOGI(TAG, "Door closeed\n");
                            vTaskDelay(300/portTICK_PERIOD_MS);
                            dooropened = false;
                            gpio_set_level(GPIO_OUTPUT_IO_2, 0);
                            vTaskDelay(300/portTICK_PERIOD_MS);
                            pwrstate = -1;
                            gpio_set_level(GPIO_OUTPUT_IO_0, 0);
                            gpio_set_level(GPIO_OUTPUT_IO_1, 0);
                            ESP_LOGI(TAG, "Key power off\n");
                            break;
                        }
                    }
                    // ESP_LOGI(TAG, "[DATA EVT]:");
                    // uart_write_bytes(ICREADER_UART_NUM, (const char*) dtmp, event.size);
                    break;
                //Event of HW FIFO overflow detected
                case UART_FIFO_OVF:
                    ESP_LOGI(TAG, "hw fifo overflow");
                    // If fifo overflow happened, you should consider adding flow control for your application.
                    // The ISR has already reset the rx FIFO,
                    // As an example, we directly flush the rx buffer here in order to read more data.
                    uart_flush_input(ICREADER_UART_NUM);
                    xQueueReset(uart2_queue);
                    break;
                //Event of UART ring buffer full
                case UART_BUFFER_FULL:
                    ESP_LOGI(TAG, "ring buffer full");
                    // If buffer full happened, you should consider increasing your buffer size
                    // As an example, we directly flush the rx buffer here in order to read more data.
                    uart_flush_input(ICREADER_UART_NUM);
                    xQueueReset(uart2_queue);
                    break;
                //Event of UART RX break detected
                case UART_BREAK:
                    ESP_LOGI(TAG, "uart rx break");
                    break;
                //Event of UART parity check error
                case UART_PARITY_ERR:
                    ESP_LOGI(TAG, "uart parity error");
                    break;
                //Event of UART frame error
                case UART_FRAME_ERR:
                    ESP_LOGI(TAG, "uart frame error");
                    break;
                //UART_PATTERN_DET
                case UART_PATTERN_DET:
                    uart_get_buffered_data_len(ICREADER_UART_NUM, &buffered_size);
                    int pos = uart_pattern_pop_pos(ICREADER_UART_NUM);
                    ESP_LOGI(TAG, "[UART PATTERN DETECTED] pos: %d, buffered size: %d", pos, buffered_size);
                    if (pos == -1) {
                        // There used to be a UART_PATTERN_DET event, but the pattern position queue is full so that it can not
                        // record the position. We should set a larger queue size.
                        // As an example, we directly flush the rx buffer here.
                        uart_flush_input(ICREADER_UART_NUM);
                    } else {
                        uart_read_bytes(ICREADER_UART_NUM, dtmp, pos, 100 / portTICK_PERIOD_MS);
                        uint8_t pat[PATTERN_CHR_NUM + 1];
                        memset(pat, 0, sizeof(pat));
                        uart_read_bytes(ICREADER_UART_NUM, pat, PATTERN_CHR_NUM, 100 / portTICK_PERIOD_MS);
                        ESP_LOGI(TAG, "read data: %s", dtmp);
                        ESP_LOGI(TAG, "read pat : %s", pat);
                    }
                    break;
                //Others
                default:
                    ESP_LOGI(TAG, "uart event type: %d", event.type);
                    break;
            }
        }
    }
    free(dtmp);
    dtmp = NULL;
    vTaskDelete(NULL);
}

static void uart1_4g_task(void *pvParameters)
{
    uart_event_t event;
    size_t buffered_size;
    uint8_t* dtmp = (uint8_t*) malloc(RD_BUF_SIZE);
    for(;;) {
        //Waiting for UART event.
        if(xQueueReceive(uart1_queue, (void * )&event, (TickType_t)portMAX_DELAY)) 
        {
            bzero(dtmp, RD_BUF_SIZE);
            ESP_LOGI(TAG, "uart[%d] event:", UART_4G_NUM);
            switch(event.type) {
                //Event of UART receving data
                /*We'd better handler data event fast, there would be much more data events than
                other types of events. If we take too much time on data event, the queue might
                be full.*/
                case UART_DATA:
                    ESP_LOGI(TAG, "[UART DATA]: %d", event.size);
                    uart_read_bytes(UART_4G_NUM, dtmp, event.size, portMAX_DELAY);
                    for(int i=0;i<event.size;i++)
                    {
                        ESP_LOGI(TAG, "[UART READ DATA[%d]]: %x\n", i, *(dtmp+i));
                    }
                    
                    if(checkData(dtmp, ota_cmd_char,0,5) || checkData(dtmp, ota_cmd_plain, 0, 10))
                    {
                        OTA_UPDATE = 1;
                        uart_write_bytes(UART_4G_NUM, (const char*) ota_update, sizeof(ota_update));
                        ESP_LOGI(TAG, "===>>>OTA-start<<<===");
                    }
                    if(checkData(dtmp, start_engine,0,12))
                    {
                        gpio_set_level(ENGINE_PIN, 1);
                        vTaskDelay(1000/portTICK_PERIOD_MS);
                        gpio_set_level(ENGINE_PIN, 0);
                        uart_write_bytes(UART_4G_NUM, (const char*) engine_started, sizeof(engine_started));
                    }
                    if(checkData(dtmp, reboot_cmd,0,6))
                    {
                        uart_write_bytes(UART_4G_NUM, (const char*) reboot_now, sizeof(reboot_now));
                        vTaskDelay(3000/portTICK_PERIOD_MS);
                        esp_restart();
                    }
                    break;
                //Event of HW FIFO overflow detected
                case UART_FIFO_OVF:
                    ESP_LOGI(TAG, "hw fifo overflow");
                    // If fifo overflow happened, you should consider adding flow control for your application.
                    // The ISR has already reset the rx FIFO,
                    // As an example, we directly flush the rx buffer here in order to read more data.
                    uart_flush_input(UART_4G_NUM);
                    xQueueReset(uart1_queue);
                    break;
                //Event of UART ring buffer full
                case UART_BUFFER_FULL:
                    ESP_LOGI(TAG, "ring buffer full");
                    // If buffer full happened, you should consider increasing your buffer size
                    // As an example, we directly flush the rx buffer here in order to read more data.
                    uart_flush_input(UART_4G_NUM);
                    xQueueReset(uart1_queue);
                    break;
                //Event of UART RX break detected
                case UART_BREAK:
                    ESP_LOGI(TAG, "uart rx break");
                    break;
                //Event of UART parity check error
                case UART_PARITY_ERR:
                    ESP_LOGI(TAG, "uart parity error");
                    break;
                //Event of UART frame error
                case UART_FRAME_ERR:
                    ESP_LOGI(TAG, "uart frame error");
                    break;
                //UART_PATTERN_DET
                case UART_PATTERN_DET:
                    uart_get_buffered_data_len(UART_4G_NUM, &buffered_size);
                    int pos = uart_pattern_pop_pos(UART_4G_NUM);
                    ESP_LOGI(TAG, "[UART PATTERN DETECTED] pos: %d, buffered size: %d", pos, buffered_size);
                    if (pos == -1) {
                        // There used to be a UART_PATTERN_DET event, but the pattern position queue is full so that it can not
                        // record the position. We should set a larger queue size.
                        // As an example, we directly flush the rx buffer here.
                        uart_flush_input(UART_4G_NUM);
                    } else {
                        uart_read_bytes(UART_4G_NUM, dtmp, pos, 100 / portTICK_PERIOD_MS);
                        uint8_t pat[PATTERN_CHR_NUM + 1];
                        memset(pat, 0, sizeof(pat));
                        uart_read_bytes(UART_4G_NUM, pat, PATTERN_CHR_NUM, 100 / portTICK_PERIOD_MS);
                        ESP_LOGI(TAG, "read data: %s", dtmp);
                        ESP_LOGI(TAG, "read pat : %s", pat);
                    }
                    break;
                //Others
                default:
                    ESP_LOGI(TAG, "uart event type: %d", event.type);
                    break;
            }
        }
    }
    free(dtmp);
    dtmp = NULL;
    vTaskDelete(NULL);
}

static void wifi_event_handler(void* arg, esp_event_base_t event_base,
                                    int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        esp_wifi_connect();
        ESP_LOGI(TAG, "retry to connect to the AP");
        // } else {
        //     xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
        // }
        ESP_LOGI(TAG,"connect to the AP fail");
        vTaskDelay(2000 / portTICK_PERIOD_MS);
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
        s_retry_num = 0;
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    }
}

void wifi_init_sta(void)
{
    s_wifi_event_group = xEventGroupCreate();
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &wifi_event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &wifi_event_handler,
                                                        NULL,
                                                        &instance_got_ip));

    wifi_config_t wifi_config = {
        .sta = {
            .ssid = ESP_WIFI_SSID,
            .password = ESP_WIFI_PASSWORD,
            /* Authmode threshold resets to WPA2 as default if password matches WPA2 standards (pasword len => 8).
             * If you want to connect the device to deprecated WEP/WPA networks, Please set the threshold value
             * to WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK and set the password with length and format matching to
             * WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK standards.
             */
            .threshold.authmode = WIFI_AUTH_WPA2_PSK,
            .sae_pwe_h2e = WPA3_SAE_PWE_BOTH,
            .sae_h2e_identifier = CONFIG_ESP_WIFI_PW_ID,
        },
    };
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));


    ESP_ERROR_CHECK(esp_wifi_start());

    ESP_LOGI(TAG, "wifi_init_sta finished.");

    /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
     * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
            WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
            pdFALSE,
            pdFALSE,
            portMAX_DELAY);

    /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
     * happened. */
    if (bits & WIFI_CONNECTED_BIT) {
        ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
                 ESP_WIFI_SSID, ESP_WIFI_PASSWORD);
    } else if (bits & WIFI_FAIL_BIT) {
        ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
                 ESP_WIFI_SSID, ESP_WIFI_PASSWORD);
    } else {
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
    }
}

//OTAtask
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
    switch (evt->event_id) {
    case HTTP_EVENT_ERROR:
        ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
        break;
    case HTTP_EVENT_ON_CONNECTED:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
        break;
    case HTTP_EVENT_HEADER_SENT:
        ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
        break;
    case HTTP_EVENT_ON_HEADER:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
        break;
    case HTTP_EVENT_ON_DATA:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
        break;
    case HTTP_EVENT_ON_FINISH:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
        break;
    case HTTP_EVENT_DISCONNECTED:
        ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED");
        break;
    case HTTP_EVENT_REDIRECT:
        ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT");
        break;
    }
    return ESP_OK;
}

void ota_task(void *pvParameter)
{
    while (1) {
        if(OTA_UPDATE==1)
        {
            ESP_LOGI(TAG, "Starting OTA example task");
        #ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF
            esp_netif_t *netif = get_example_netif_from_desc(bind_interface_name);
            if (netif == NULL) {
                ESP_LOGE(TAG, "Can't find netif from interface description");
                abort();
            }
            struct ifreq ifr;
            esp_netif_get_netif_impl_name(netif, ifr.ifr_name);
            ESP_LOGI(TAG, "Bind interface name is %s", ifr.ifr_name);
        #endif
            esp_http_client_config_t config = {
                .url = FIRMWARE_UPGRADE_URL,
        // #ifdef CONFIG_EXAMPLE_USE_CERT_BUNDLE
                .crt_bundle_attach = esp_crt_bundle_attach,
        // #else
        //         .cert_pem = (char *)server_cert_pem_start,
        // #endif /* CONFIG_EXAMPLE_USE_CERT_BUNDLE */
        //         .event_handler = _http_event_handler,
        //         .keep_alive_enable = true,
        // #ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF
        //         .if_name = &ifr,
        // #endif
            };

            esp_https_ota_config_t ota_config = {
                .http_config = &config,
            };
            ESP_LOGI(TAG, "Attempting to download update from %s", config.url);
            esp_err_t ret = esp_https_ota(&ota_config);
            if (ret == ESP_OK) {
                ESP_LOGI(TAG, "OTA Succeed, Rebooting...");
                uart_write_bytes(UART_4G_NUM, (const char*) reboot_now, sizeof(reboot_now));
                esp_restart();
            } else {
                ESP_LOGE(TAG, "Firmware upgrade failed");
            }
        }
        ESP_LOGI(TAG, "OTA task is ready"); 
        vTaskDelay(5000 / portTICK_PERIOD_MS);
    }
}

void app_main(void)
{
    ESP_LOGI(TAG, "Starting WiFi key");
    ESP_ERROR_CHECK(nvs_flash_init());
    configure_led(TAG);
    ESP_LOGI(TAG, "WiFi key server started");
    //校验卡类型：04 0C 02 20 00 04 00
    icreader_init();

    /* Configure parameters of an UART driver,
     * communication pins and install the driver */
    uart_config_t uart_icreader_config = {
        .baud_rate = 9600,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_DEFAULT,
    };
    //Install UART driver, and get the queue.
    uart_driver_install(ICREADER_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart2_queue, 0);
    uart_param_config(ICREADER_UART_NUM, &uart_icreader_config);

    //Set UART pins (using UART0 default pins ie no changes.)
    uart_set_pin(ICREADER_UART_NUM, UART2_TX_NUM, UART2_RX_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

    //Set uart pattern detect function.
    uart_enable_pattern_det_baud_intr(ICREADER_UART_NUM, '+', PATTERN_CHR_NUM, 9, 0, 0);
    //Reset the pattern queue length to record at most 20 pattern positions.
    uart_pattern_queue_reset(ICREADER_UART_NUM, 20);

    uart_config_t uart_4g_config = {
        .baud_rate = 9600,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_DEFAULT,
    };
    //Install UART driver, and get the queue.
    uart_driver_install(UART_4G_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart1_queue, 0);
    uart_param_config(UART_4G_NUM, &uart_4g_config);

    //Set UART pins (using UART0 default pins ie no changes.)
    uart_set_pin(UART_4G_NUM, UART1_TX_NUM, UART1_RX_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

    // //Set uart pattern detect function.
    // uart_enable_pattern_det_baud_intr(UART_4G_NUM, '+', PATTERN_CHR_NUM, 9, 0, 0);
    // //Reset the pattern queue length to record at most 20 pattern positions.
    // uart_pattern_queue_reset(UART_4G_NUM, 20);

    //Create a task to handler UART event from ISR
    xTaskCreate(uart2_icreader_task, "uart2toICreader", 2048, NULL, 12, NULL);
    xTaskCreate(uart1_4g_task, "uart1to4g", 2048, NULL, 12, NULL);
    xTaskCreate(&ota_task, "ota_task", 8192, NULL, 5, NULL);
    vTaskDelay(pdMS_TO_TICKS(PING_PERIOD_MS));

    //CAN
    //Create tasks, queues, and semaphores
    rx_task_queue = xQueueCreate(1, sizeof(rx_task_action_t));
    tx_task_queue = xQueueCreate(1, sizeof(tx_task_action_t));
    ctrl_task_sem = xSemaphoreCreateBinary();
    stop_ping_sem = xSemaphoreCreateBinary();
    done_sem = xSemaphoreCreateBinary();
    xTaskCreatePinnedToCore(twai_receive_task, "TWAI_rx", 4096, NULL, RX_TASK_PRIO, NULL, tskNO_AFFINITY);
    xTaskCreatePinnedToCore(twai_transmit_task, "TWAI_tx", 4096, NULL, TX_TASK_PRIO, NULL, tskNO_AFFINITY);
    xTaskCreatePinnedToCore(twai_control_task, "TWAI_ctrl", 4096, NULL, CTRL_TSK_PRIO, NULL, tskNO_AFFINITY);
    // ESP_ERROR_CHECK(twai_start());

    // xTaskCreatePinnedToCore(esp_wifi_start, "esp_wifi_start", 4096, NULL, 10, NULL, tskNO_AFFINITY);

    //Install TWAI driver
    ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config));
    ESP_LOGI(EXAMPLE_TAG, "Driver installed");
    xSemaphoreGive(ctrl_task_sem);              //Start control task
    // xSemaphoreTake(done_sem, portMAX_DELAY);    //Wait for completion
    wifi_init_sta();
}